#pragma once
#include <assert.h>
#include <functional>
#include "Sock.hpp"
#include "Epoll.hpp"
const static uint16_t gport = 8080;
using func_t = std::function<std::string(std::string)>;
class EpollServer
{
    const static int maxsize = 20;

public:
    EpollServer(func_t func,uint16_t port = gport) : func_(func),port_(port)
    {
    }
    void InitServer()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        ep_.Create(); // 创建epoll实例
    }
    void Start()
    {
        bool r = ep_.AddEvent(listensock_.Fd(), EPOLLIN); // 添加读事件
        assert(r);
        (void)r; // 使调试通过
        while (true)
        {
            // 1.能够直接进行accept吗？不行，需要epoll进行管理
            int timeout = -1;
            int n = ep_.Wait(events_, maxsize, timeout);
            switch (n)
            {
            case -1:
                logMessage(Warning, "epoll_wait fialed，code:%d,string:%s", errno, strerror(errno));
                break;
            case 0:
                logMessage(Debug, "epoll_wait timeout，code:%d,string:%s", errno, strerror(errno));
                break;
            default:
                HandlerEvents(n);
                break;
            }
        }
    }
    void HandlerEvents(int num)
    {
        logMessage(Debug,"有%d个事件就绪",num);
        for (int i = 0; i < num; i++)
        {
            // logMessage(Fatal, "新的连接到来...");
            int fd = events_[i].data.fd;
            uint32_t event = events_[i].events;
            logMessage(Debug,"当前正在处理%d上的%s",fd,(event & EPOLLIN) ? "EPOLLIN" : "OTHER");
            if (event & EPOLLIN)
            {
                // 1.处理新连接
                if (fd == listensock_.Fd())
                {
                    std::string clientip;
                    uint16_t clientport;
                    int sock = listensock_.Accept(&clientip, &clientport);
                    logMessage(Debug, "%s:%d 已经连上服务器", clientip.c_str(), clientport);
                    // 1.1此时这里能不能进行read/recv呢？不行，只有epoll知道sock上面的事件情况，将sock添加到epoll中
                    if (sock < 0)
                        continue;
                    int r = ep_.AddEvent(sock, EPOLLIN); // 添加读事件
                    assert(r);
                    (void)r;
                }
                else // 2.读取事件
                {
                    char buffer[1024];
                    ssize_t s = recv(fd, buffer, sizeof(buffer) - 1, 0); // 不会被阻塞
                    if (s > 0)
                    {
                        // ServerIO
                        buffer[s - 1] = 0;
                        buffer[s - 2] = 0;  //这个xshell字符串以"\r\n"结尾
                        std::string request = buffer;
                        std::cout << "client#" << request.c_str() << std::endl;
                        // std::string message = buffer;
                        // message += "[epoll server echo]\r\n";
                        // send(fd, message.c_str(), message.size(), 0);

                        //小型服务器初版
                        std::string response = func_(request);
                        send(fd, response.c_str(), response.size(), 0);
                    }
                    else
                    {
                        if (s == 0)
                        {
                            logMessage(Info, "client quit...");
                        }
                        else
                        {
                            logMessage(Warning, ",recv error,code:%d,string:%s", errno, strerror(errno));
                        }
                       //注意：先从epoll中移除fd，再close fd
                       ep_.DelEvent(fd);
                       close(fd);
                    }
                }
            }
        }
    }
    ~EpollServer()
    {
        listensock_.Close();
        ep_.Close();
    }

private:
    uint16_t port_;
    Sock listensock_;
    Epoll ep_;
    struct epoll_event events_[maxsize];
    func_t func_;
};